Skip to content

fix(security): phase-1 agent VM harden (keep NAT, defer private cutover)#9261

Draft
Git-on-my-level wants to merge 5 commits into
mainfrom
fix/agent-vm-private-network
Draft

fix(security): phase-1 agent VM harden (keep NAT, defer private cutover)#9261
Git-on-my-level wants to merge 5 commits into
mainfrom
fix/agent-vm-private-network

Conversation

@Git-on-my-level

@Git-on-my-level Git-on-my-level commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Phase-1, low-blast-radius harden for agent VM public :8080 exposure (#7326) — without removing public NAT or applying a public DENY firewall (those break prod today).

Why not private-only yet: agent VMs are on VPC default; agent-proxy is on GKE omi-prod-vpc-1 with no peering. Desktop still calls http://{vmIP}:8080 for upload/sync. Removing NAT or denying 0.0.0.0/0 would break chat + DB sync.

This PR (safe to merge)

  • Keep ONE_TO_ONE_NAT / public IP provisioning
  • Keep / contract-test omi-agent-vm network tag
  • Auth-gate VM /health (was publicly readable databaseReady); update desktop + agent-proxy callers
  • Land deferred phase-3 firewall IaC with apply refuse-by-default (AGENT_VM_FIREWALL_APPLY_PHASE3 gate)
  • Docs in AGENTS.md describing the deferred cutover

Explicitly deferred (do not apply yet)

Step Follow-up
Route desktop upload/sync through agent-proxy PR10c (required before firewall cutover)
Allowlist reserved Cloud NAT egress for proxy (or peer/move VMs) infra
Apply public DENY / remove NAT phase 3 after the above are proven

Related: #6611
Closes: partial progress on #7326 (auth harden + prepare surface; not full network isolation)

Test plan

cd desktop/macos/Backend-Rust && cargo test agent::contract
# 2 passed

cd backend && python3 -m pytest tests/unit/test_agent_vm_firewall_contract.py -v
# 4 passed (includes apply-script refuse gate)

bash backend/scripts/apply-agent-vm-firewall.sh
# must exit 1 with REFUSED (no gate env)

After merge / deploy (auth path):

  1. Publish updated desktop/macos/agent-cloud/agent.mjs to the agent GCS artifact bucket (VMs hot-reload from GCS).
  2. Deploy agent-proxy + desktop-backend as needed for caller header changes.
  3. Confirm unauthenticated GET http://<vm-public-ip>:8080/health401.
  4. Confirm authenticated health (Bearer / ?token=) → 200 with databaseReady.
  5. Smoke: desktop agent provision → DB upload/sync still works; chat via wss://agent.omi.me still works.

Do not run apply-agent-vm-firewall.sh or --live reachability against prod until PR10c + private reachability land.

Merge with a regular merge (no squash).

Made with Cursor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5ad7e46dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/macos/Backend-Rust/src/routes/agent.rs Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 6 files

Confidence score: 2/5

  • In desktop/macos/Backend-Rust/src/routes/agent.rs, removing accessConfigs means create_gce_vm can no longer produce an external IP while its Result<String> contract and downstream consumers still treat it as reachable over public network; merging as-is is likely to break agent provisioning/reachability flows — either restore external IP assignment or change the return contract and all callers before merging.
  • AGENTS.md describes agent-vm-firewall as denying only public tcp:8080, but backend/charts/agent-vm-firewall/firewall-rule.yaml uses sourceRanges: [0.0.0.0/0] on a DENY ingress rule, which effectively blocks that port from everywhere and can cut off intended internal access paths — align the rule or documentation to the intended policy and verify expected traffic still works.
  • backend/scripts/agent-vm-reachability-check.sh relies on Python assert for firewall contract checks, and backend/scripts/apply-agent-vm-firewall.sh validates only DENY while not enforcing full contract fields (like ingress/public source ranges), so CI/deploy validation can silently pass unsafe or incorrect rules in some environments — replace assert with explicit runtime checks and enforce all security-critical fields before merging.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread desktop/macos/Backend-Rust/src/routes/agent.rs Outdated
Comment thread AGENTS.md Outdated
Comment thread backend/scripts/agent-vm-reachability-check.sh Outdated
Comment thread backend/scripts/apply-agent-vm-firewall.sh Outdated
@Git-on-my-level Git-on-my-level marked this pull request as draft July 8, 2026 02:13
Git-on-my-level and others added 3 commits July 8, 2026 14:55
Remove ONE_TO_ONE_NAT accessConfigs from GCE insert payload so new
agent VMs are private-network only. Add Rust contract test guarding
the provision JSON shape.

Verification: cd desktop/macos/Backend-Rust && cargo test provision

Related #7326

Co-authored-by: Cursor <cursoragent@cursor.com>
Add GCP firewall IaC for tag omi-agent-vm that denies public tcp:8080,
with apply/reachability scripts and hermetic contract tests. Extend the
Rust provision JSON contract to assert omi-agent-vm tagging and no public
IP fields in the insert payload.

Verification:
  cd desktop/macos/Backend-Rust && cargo test provision
  cd backend && python3 -m pytest tests/unit/test_agent_vm_firewall_contract.py -v
  backend/scripts/agent-vm-reachability-check.sh

Closes #7326

Related #6611

Co-authored-by: Cursor <cursoragent@cursor.com>
@Git-on-my-level Git-on-my-level force-pushed the fix/agent-vm-private-network branch from f5ad7e4 to d77624e Compare July 8, 2026 08:03
@Git-on-my-level

Copy link
Copy Markdown
Collaborator Author

Monitor follow-up for PR #9261:

  • Updated agent VM readiness/restart recovery to store the VM's private networkIP instead of falling back to missing public natIP / unknown after removing NAT.
  • Split the firewall contract into a higher-priority private tcp:8080 ALLOW plus public 0.0.0.0/0 DENY so agent-proxy/VPC traffic remains reachable.
  • Replaced optimized-away live-check assert statements with explicit SystemExit failures and expanded apply-time firewall contract validation.
  • Resolved the five addressed review threads.

Verification passed:

  • backend/scripts/agent-vm-reachability-check.sh under PYTHONOPTIMIZE=1: 6 passed
  • cargo test agent: 2 passed
  • cargo fmt --check
  • git diff --check
  • post-push GitHub checks all completed successfully or skipped as expected
  • post-push trusted-thread re-scan found no unresolved trusted bot threads

Git-on-my-level and others added 2 commits July 12, 2026 00:57
Keep public NAT and tag omi-agent-vm; gate firewall apply as deferred
phase-3. Auth-gate VM /health and update desktop + agent-proxy callers.

Verification:
  cargo test agent::contract
  python3 -m pytest backend/tests/unit/test_agent_vm_firewall_contract.py -v

Related #7326

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@Git-on-my-level Git-on-my-level changed the title fix(agent): provision agent VMs without public NAT fix(security): phase-1 agent VM harden (keep NAT, defer private cutover) Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant